package com.jfshop.framework.util;

import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;


/**
 * 
 * Name: EncryptUtil.java
 * ProjectName: [Framework-Base]
 * Package: [com.grandthink.framework.util.EncryptUtil.java]
 * Description: 加密工具类  
 * 
 * @since JDK1.6
 * @see
 * @version [v1.0]
 *
 * Author: @author: Thunder
 * Date: 2013年12月5日 上午9:34:49
 *
 * Update-User: @author
 * Update-Time:
 * Update-Remark:
 * 
 * Check-User:
 * Check-Time:
 * Check-Remark:
 * 
 * Company: GrandThink
 * Copyright: GrandThink
 */
public final class EncryptUtil {

	public static final String ENCRYPT_MD5 = "md5";
	public static final String ENCRYPT_HMAC_MD5 = "HmacMD5";

	private EncryptUtil() {
		throw new RuntimeException("util class is static");
	}

	/**
	 * 对数据执行MD5散列
	 * @param data       需要散列的数据
	 * @return           返回散列码字符串数据
	 */
	public static String md5(String data) {
		return byteToString(md5(data.getBytes()));
	}

	/**
	 * 对数据执行MD5散列
	 * @param data       需要散列的数据
	 * @return           返回散列码二进制数据
	 */
	public static byte[] md5(byte[] data) {
		MessageDigest md5 = null;
		try {
			md5 = MessageDigest.getInstance(ENCRYPT_MD5);
		} catch (NoSuchAlgorithmException e) {
			return null;
		}
		md5.update(data);
		return md5.digest();
	}

	/**
	 * 对数据执行HMAC加密
	 * @param data          需要加密的数据
	 * @return              返回加密后的字符串数据
	 */
	public static String hmac(String data, String key) {
		SecretKeySpec sk = new SecretKeySpec(key.getBytes(), ENCRYPT_HMAC_MD5);
		Mac mac = null;
		try {
			mac = Mac.getInstance(ENCRYPT_HMAC_MD5);
			mac.init(sk);
			return byteToString(mac.doFinal(md5(data).getBytes()));
		} catch (NoSuchAlgorithmException e) {
			return null;
		} catch (InvalidKeyException e) {
			return null;
		}
	}

	/**
	 * 把byte[]转换成字符串
	 * @param data          需要转换的byte[]数组
	 * @return              返回转换后的字符串数据
	 */
	private static String byteToString(byte[] data) {
		StringBuilder result = new StringBuilder();
		for (int i = 0; i < data.length; i++) {
			String tmp = Integer.toHexString(data[i] & 0xFF);
			if (tmp.length() == 1) {
				result.append("0" + tmp);
			} else {
				result.append(tmp);
			}
		}
		return result.toString();
	}
	
	/**
	 * 
	 * Name: Des3.java
	 * ProjectName: [Framework-Base]
	 * Package: [com.grandthink.framework.util.EncryptUtil.java]
	 * Description: 3DES 加密算法  
	 * 
	 * @since JDK1.6
	 * @see
	 * @version [v1.0]
	 *
	 * Author: @author: Thunder
	 * Date: 2013年12月27日 下午5:43:20
	 *
	 * Update-User: @author
	 * Update-Time:
	 * Update-Remark:
	 * 
	 * Check-User:
	 * Check-Time:
	 * Check-Remark:
	 * 
	 * Company: GrandThink
	 * Copyright: GrandThink
	 */
	public static class Des3 {
		
		private static final String DEFAULT_KEY = "AWJkpGfmZ+hpamstbL5vcHMyd3R1dnd4";
		private static final byte[] DEFAULT_IV = new byte[] { 14, 32, 55, 1, 27, 91, 73, 89 };
		
		/** 加密模型枚举类 */
		public enum DesType {
			ECB, CBC
		}
		
		/**
		 * DES3加密
		 * NOTIC: 使用默认的KEY
		 * @param data  需要加密的字符串数据
		 * @param type  加密的类型
		 * @return      加密后的字符串
		 */
		public static String encode(String data, DesType type) {
			return encode(DEFAULT_KEY, data, type).replace("\r\n", "");
		}
		
		/**
		 * DES3加密
		 * @param key   加密的KEY
		 * @param data  需要加密的字符串数据
		 * @param type  加密的类型
		 * @return      加密后的字符串
		 */
		public static String encode(String key, String data, DesType type) {
			switch (type) {
			case ECB:
				return encodeECB(key, data).replace("\r\n", "");
			case CBC:
				return encodeCBC(key, data).replace("\r\n", "");
			default:
				break;
			}
			return null;
		}
		
		/**
		 * DES3解密
		 * NOTIC: 使用默认的KEY
		 * @param data   需要解密的字符串数据
		 * @param type   解密类型
		 * @return       解密后的数据
		 */
		public static String decode(String data, DesType type) {
			return decode(DEFAULT_KEY, data, type);
		}
		
		/**
		 * DES3解密
		 * @param key    解密KEY
		 * @param data   需要解密的字符串数据
		 * @param type   解密类型
		 * @return       解密后的数据
		 */
		public static String decode(String key, String data, DesType type) {
			switch (type) {
			case ECB:
				return decodeECB(key, data);
			case CBC:
				return decodeCBC(key, data);
			default:
				break;
			}
			return null;
		}
		
		/**
		 * DES3加密(ECB模型)
		 * NOTIC: 使用默认的KEY
		 * @param data      需要加密的字符串数据
		 * @return          加密后的数据
		 */
		public static String encodeECB(String data) {
			return encodeECB(DEFAULT_KEY, data).replace("\r\n", "");
		}
		
		/**
		 * DES3加密(ECB模型)
		 * @param key       加密KEY
		 * @param data      需要加密的字符串数据
		 * @return          加密后的数据
		 */
		public static String encodeECB(String key, String data) {
			if (StringUtil.isEmptyOrNull(key) || StringUtil.isEmptyOrNull(data)) return null;
			try {
				byte[] byteKey = new BASE64Decoder().decodeBuffer(key);
				final byte[] byteData = data.getBytes("UTF-8");
				return new BASE64Encoder().encode(encodeECB(byteKey, byteData));
			} catch (IOException e) {
				e.printStackTrace();
			}
			return null;
		}
		
		/**
		 * DES3解密(ECB模型)
		 * NOTIC: 使用默认的KEY
		 * @param data      需要解密的字符串数据
		 * @return          解密后的数据
		 */
		public static String decodeECB(String data) {
			return decodeECB(DEFAULT_KEY, data);
		}
		
		/**
		 * DES3解密(ECB模型)
		 * @param key       解密KEY
		 * @param data      需要解密的字符串数据
		 * @return          解密后的数据
		 */
		public static String decodeECB(String key, String data) {
			if (StringUtil.isEmptyOrNull(key) || StringUtil.isEmptyOrNull(data)) return null;
			try {
				final BASE64Decoder decoder = new BASE64Decoder();
				byte[] byteKey = decoder.decodeBuffer(key);
				final byte[] byteData = decoder.decodeBuffer(data);
				return new String(decodeECB(byteKey, byteData), "UTF-8");
			} catch (IOException e) {
				e.printStackTrace();
			}
			return null;
		}
		
		/**
	     * ECB加密,不要IV
	     * @param key 密钥
	     * @param data 明文
	     * @return Base64编码的密文
	     */
	    public static byte[] encodeECB(byte[] key, byte[] data)  {
			try {
			    Key deskey = null;
			    
			    final DESedeKeySpec spec = new DESedeKeySpec(key);
				SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede");
		        deskey = keyfactory.generateSecret(spec);
		 
		        final Cipher cipher = Cipher.getInstance("desede" + "/ECB/PKCS5Padding");
		        cipher.init(Cipher.ENCRYPT_MODE, deskey);
		 
		        return cipher.doFinal(data);
			} catch (InvalidKeyException e) {
				e.printStackTrace();
			} catch (NoSuchAlgorithmException e) {
				e.printStackTrace();
			} catch (InvalidKeySpecException e) {
				e.printStackTrace();
			} catch (NoSuchPaddingException e) {
				e.printStackTrace();
			} catch (IllegalBlockSizeException e) {
				e.printStackTrace();
			} catch (BadPaddingException e) {
				e.printStackTrace();
			}
			return null;
	    }
	 
	    /**
	     * ECB解密,不要IV
	     * @param key 密钥
	     * @param data Base64编码的密文
	     * @return 明文
	     */
	    public static byte[] decodeECB(byte[] key, byte[] data) {
			try {
				Key deskey = null;
		        
		        final DESedeKeySpec spec = new DESedeKeySpec(key);
				
		        final SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede");
		        deskey = keyfactory.generateSecret(spec);
		 
		        final  Cipher cipher = Cipher.getInstance("desede" + "/ECB/PKCS5Padding");
		        cipher.init(Cipher.DECRYPT_MODE, deskey);
		 
		        return cipher.doFinal(data);
			} catch (InvalidKeyException e) {
				e.printStackTrace();
			} catch (NoSuchAlgorithmException e) {
				e.printStackTrace();
			} catch (InvalidKeySpecException e) {
				e.printStackTrace();
			} catch (NoSuchPaddingException e) {
				e.printStackTrace();
			} catch (IllegalBlockSizeException e) {
				e.printStackTrace();
			} catch (BadPaddingException e) {
				e.printStackTrace();
			}
	        return null;
	    }
	    
	    /**
		 * DES3加密(CBC模型)
		 * NOTIC: 使用默认的KEY
		 * @param data      需要加密的字符串数据
		 * @return          加密后的数据
		 */
	    public static String encodeCBC(String data) {
			return encodeCBC(DEFAULT_KEY, data).replace("\r\n", "");
		}
		
	    /**
		 * DES3加密(CBC模型)
		 * @param key       加密KEY
		 * @param data      需要加密的字符串数据
		 * @return          加密后的数据
		 */
		public static String encodeCBC(String key, String data) {
			if (StringUtil.isEmptyOrNull(key) || StringUtil.isEmptyOrNull(data)) return null;
			try {
				final byte[] byteKey = new BASE64Decoder().decodeBuffer(key);
				final byte[] byteData = data.getBytes("UTF-8");
				return new BASE64Encoder().encode(encodeCBC(byteKey, DEFAULT_IV, byteData));
			} catch (IOException e) {
				e.printStackTrace();
			}
			return null;
		}
		
		/**
		 * DES3解密(CBC模型)
		 * NOTIC: 使用默认的KEY
		 * @param data      需要解密的字符串数据
		 * @return          解密后的数据
		 */
		public static String decodeCBC(String data) {
			return decodeCBC(DEFAULT_KEY, data);
		}
		
		/**
		 * DES3解密(CBC模型)
		 * @param key       解密KEY
		 * @param data      需要解密的字符串数据
		 * @return          解密后的数据
		 */
		public static String decodeCBC(String key, String data) {
			if (StringUtil.isEmptyOrNull(key) || StringUtil.isEmptyOrNull(data)) return null;
			try {
				final BASE64Decoder decoder = new BASE64Decoder();
				final byte[] byteKey = decoder.decodeBuffer(key);
				final byte[] byteData = decoder.decodeBuffer(data);
				return new String(decodeCBC(byteKey, DEFAULT_IV, byteData), "UTF-8");
			} catch (IOException e) {
				e.printStackTrace();
			}
			return null;
		}
	 
	    /**
	     * CBC加密
	     * @param key 密钥
	     * @param keyiv IV
	     * @param data 明文
	     * @return Base64编码的密文
	     */
	    public static byte[] encodeCBC(byte[] key, byte[] keyiv, byte[] data) {
			try {
				Key deskey = null;
			    final DESedeKeySpec spec = new DESedeKeySpec(key);
				
			    final SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede");
			    deskey = keyfactory.generateSecret(spec);
			 
			    final Cipher cipher = Cipher.getInstance("desede" + "/CBC/PKCS5Padding");
			    final IvParameterSpec ips = new IvParameterSpec(keyiv);
			    cipher.init(Cipher.ENCRYPT_MODE, deskey, ips);
			 
		        return cipher.doFinal(data);
			} catch (InvalidKeyException e) {
				e.printStackTrace();
			} catch (NoSuchAlgorithmException e) {
				e.printStackTrace();
			} catch (InvalidKeySpecException e) {
				e.printStackTrace();
			} catch (NoSuchPaddingException e) {
				e.printStackTrace();
			} catch (InvalidAlgorithmParameterException e) {
				e.printStackTrace();
			} catch (IllegalBlockSizeException e) {
				e.printStackTrace();
			} catch (BadPaddingException e) {
				e.printStackTrace();
			}
			return null;
	    }
	 
	    /**
	     * CBC解密
	     * @param key 密钥
	     * @param keyiv IV
	     * @param data Base64编码的密文
	     * @return 明文
	     */
	    public static byte[] decodeCBC(byte[] key, byte[] keyiv, byte[] data) {
			try {
				Key deskey = null;
				final DESedeKeySpec spec = new DESedeKeySpec(key);
				
				final SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede");
		        deskey = keyfactory.generateSecret(spec);
		 
		        final Cipher cipher = Cipher.getInstance("desede" + "/CBC/PKCS5Padding");
		        final IvParameterSpec ips = new IvParameterSpec(keyiv);
		        cipher.init(Cipher.DECRYPT_MODE, deskey, ips);
		 
		        return cipher.doFinal(data);
			} catch (InvalidKeyException e) {
				e.printStackTrace();
			} catch (NoSuchAlgorithmException e) {
				e.printStackTrace();
			} catch (InvalidKeySpecException e) {
				e.printStackTrace();
			} catch (NoSuchPaddingException e) {
				e.printStackTrace();
			} catch (InvalidAlgorithmParameterException e) {
				e.printStackTrace();
			} catch (IllegalBlockSizeException e) {
				e.printStackTrace();
			} catch (BadPaddingException e) {
				e.printStackTrace();
			}
	        return null;
	    }
		
	}

}
